/*-*
 * FILENAME  :
 *    $HeadURL$
 *
 * STATUS  :
 *    $Revision$
 *
 *    $Author$
 *    $Date$
 *  
 *    
 * Copyright (c) 2011 Gonalge Ltda. All rights reserved.
 *
 ****************************************************************/

package org.gonalge.arbolrojonegro.presentacion;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.Timer;

import java.awt.Color;
import java.awt.Font;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import org.apache.commons.lang.math.NumberUtils;
import org.gonalge.arbolrojonegro.dto.Nodo;
import org.gonalge.arbolrojonegro.negocio.ArbolRojoNegro;
import org.gonalge.arbolrojonegro.type.CasoArbol;
import org.gonalge.arbolrojonegro.util.FormUtils;

/**
 * 
 * @author Geremias Gonzalez
 */
public class FormPractica extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = -6793976388350611965L;

    private int elemento = 0;

    private int indexArbol = 0;

    private int indexPaso = 0;

    private int indexCasoChar = 0;

    private int indexHistorialArbol = 0;

    private boolean pasoPasoBool = true;

    private boolean subArbolBool = true;

    private CasoArbol caso;

    private boolean existeSeguientePasoBool = true;

    private final PintarArbol pintarArbol = new PintarArbol();

    private final PintarArbol pintarSubArbol = new PintarArbol();

    private ArbolRojoNegro arbolRojoNegro = new ArbolRojoNegro();

    private final JButton insertarButton = new JButton();

    private final JButton pasoSiguienteButton = new JButton();

    private final JButton pasoAtrazButton = new JButton();

    private final JButton directoButton = new JButton();

    private final JButton atrazButton = new JButton();

    private final JButton siguienteButton = new JButton();

    private final JButton historialButton = new JButton();

    private final JButton existeButton = new JButton();

    private final JButton nivelButton = new JButton();

    private final JButton nuevoButton = new JButton();

    private final JButton salirButton = new JButton();

    private final JTextArea textArea = new JTextArea();

    private final JLabel tituoLabel = new JLabel();

    private final JLabel preguntaLabel = new JLabel();

    private final JLabel elementoLabel = new JLabel();

    private final JLabel respuestaLabel = new JLabel();

    private final JLabel pasoActualLabel = new JLabel();

    private final JLabel nodosLabel = new JLabel();

    private final JLabel pasoLabel = new JLabel("PASOS");

    private final JTextField insertarEleText = new JTextField("0");

    private final JTextField buscarEleText = new JTextField("0");

    private final JSlider vertical = new JSlider();

    private final JSlider horizontal = new JSlider();

    private final JSlider horizantalSub = new JSlider();

    private final JSlider verticalSub = new JSlider();

    private final Panel panelArbol = new Panel();

    private final Panel panelSubArbol = new Panel();

    private final Panel panelSeparator1 = new Panel();

    private final Panel panelSeparator2 = new Panel();

    public Timer tiempo = new Timer(50, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            pintarArbol.setBounds(-20 * horizontal.getValue() + 660, -10 * vertical.getValue() - 10, pintarArbol.getWidth(), pintarArbol.getHeight());
            pintarSubArbol.setBounds(-10 * horizantalSub.getValue() - 50, -5 * verticalSub.getValue() - 10, pintarSubArbol.getWidth(), pintarSubArbol.getHeight());
        }
    });

    public Timer tiempo2 = new Timer(-100, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (subArbolBool) {
                pintarSubArbol.pintarSubArbol(caso);
            } else {
                pintarSubArbol.SuArbolP2();
                textArea.setText("El Nodo B Es la nueva Raiz y A-C dependen de el");
            }
        }
    });

    public Timer tiempo3 = new Timer(-100, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent p) {
            pintarArbol.pintarSubArbol3(pintarSubArbol.getArbol().getEle());
            if (existeSeguientePasoBool == true) {
                pintarSubArbol.pintarCaso2();
                pintarSubArbol.pintar();
            }
        }
    });

    public FormPractica() {
        try {
            jbInit();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void jbInit() throws Exception {
        this.getContentPane().setLayout(null);
        this.setTitle("Tutor Arbol Rojo y Negro");
        this.getContentPane().setBackground(FormUtils.getColorFondo());
        this.setBounds(FormUtils.crearRectangle(this));

        panelSeparator1.setLayout(null);
        panelSeparator1.setBackground(FormUtils.getColorFondo());
        panelSeparator1.setBounds(new Rectangle(395, 15, 10, 390));

        panelSeparator2.setLayout(null);
        panelSeparator2.setBackground(FormUtils.getColorFondo());
        panelSeparator2.setBounds(new Rectangle(15, 395, 390, 10));

        JScrollPane scrool = new JScrollPane(textArea);
        scrool.setBounds(new Rectangle(125, 590, 625, 135));
        scrool.setBackground(FormUtils.getColorFondo());

        textArea.setBackground(FormUtils.getColorFondo());
        FormUtils.updateFontLavel(textArea);
        textArea.setForeground(Color.BLACK);
        textArea.setEditable(false);

        panelArbol.setBounds(new Rectangle(30, 30, 715, 555));
        panelSubArbol.setBounds(new Rectangle(35, 35, 365, 365));
        panelArbol.setBackground(FormUtils.getColorFondo());
        panelArbol.setLayout(null);
        panelSubArbol.setBackground(FormUtils.getColorFondo());
        panelSubArbol.setLayout(null);

        FormUtils.updateButton(getClass(), insertarButton, "insertar1", "insertar2", 820, 190);
        insertarButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionInsertar();
            }
        });

        FormUtils.updateButton(getClass(), pasoSiguienteButton, "siguiente1", "siguiente2", 880, 290);
        pasoSiguienteButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionPasoSiguiente();
            }
        });

        FormUtils.updateButton(getClass(), directoButton, "directo1", "directo2", 820, 240);
        directoButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionDirecto();
            }
        });

        FormUtils.updateButton(getClass(), pasoAtrazButton, "atraz1", "atraz2", 810, 290);
        pasoAtrazButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionPasoAtraz();
            }
        });

        FormUtils.updateButton(getClass(), nuevoButton, "nuevo1_1", "nuevo1_2", 820, 100);
        nuevoButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionNuevo();
            }
        });

        FormUtils.updateButton(getClass(), atrazButton, "atraz1", "atraz2", 810, 160);
        atrazButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionAtraz();
            }
        });

        FormUtils.updateButton(getClass(), siguienteButton, "siguiente1", "siguiente2", 880, 160);
        siguienteButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionSiguiente();
            }
        });

        FormUtils.updateButton(getClass(), historialButton, "historial1", "historial2", 820, 580);
        historialButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionHistorial();
            }
        });

        FormUtils.updateButton(getClass(), existeButton, "existe1", "existe2", 820, 395);
        existeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionExiste();
            }
        });

        FormUtils.updateButton(getClass(), nivelButton, "nivel1", "nivel2", 820, 420);
        nivelButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actionNivel();
            }
        });

        FormUtils.updateButton(getClass(), salirButton, "salir1", "salir2", 890, 630);
        salirButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setVisible(false);
            }
        });

        FormUtils.updateTextFieldNumero(buscarEleText, 900, 370);
        FormUtils.updateTextFieldNumero(insertarEleText, 915, 190);

        pasoLabel.setBounds(820, 270, 175, 20);
        FormUtils.updateFontLavel(pasoLabel);
        pasoLabel.setVisible(false);
        pasoAtrazButton.setVisible(false);
        pasoSiguienteButton.setVisible(false);

        pasoActualLabel.setBounds(new Rectangle(5, 590, 110, 20));
        FormUtils.updateFontLavel(pasoActualLabel);
        pasoActualLabel.setText("Paso Actual :");

        tituoLabel.setText("ARBOL ROJO Y NEGRO");
        tituoLabel.setBounds(new Rectangle(790, 10, 170, 20));
        tituoLabel.setForeground(FormUtils.getColorTitulo());
        tituoLabel.setFont(new Font("Tahoma", 1, 14));

        preguntaLabel.setText("PREGUNTAS SOBRE");
        preguntaLabel.setBounds(new Rectangle(820, 330, 170, 25));
        FormUtils.updateFontLavel(preguntaLabel);
        preguntaLabel.setHorizontalAlignment(JTextField.CENTER);

        nodosLabel.setText("LOS NODOS");
        nodosLabel.setBounds(new Rectangle(820, 345, 170, 25));
        FormUtils.updateFontLavel(nodosLabel);
        nodosLabel.setHorizontalAlignment(JTextField.CENTER);

        elementoLabel.setText("ELEMENTO :");
        elementoLabel.setBounds(new Rectangle(820, 370, 175, 25));
        FormUtils.updateFontLavel(elementoLabel);

        respuestaLabel.setBounds(new Rectangle(820, 455, 240, 25));
        respuestaLabel.setForeground(FormUtils.getColorTitulo());
        FormUtils.updateFontLavel(respuestaLabel);

        vertical.setOrientation(JSlider.VERTICAL);
        vertical.setBounds(new Rectangle(0, 15, 15, 570));
        vertical.setValue(0);
        vertical.setInverted(true);
        vertical.setBackground(FormUtils.getColorFondo());

        horizontal.setBounds(new Rectangle(15, 0, 730, 15));
        horizontal.setBackground(FormUtils.getColorFondo());

        horizantalSub.setBounds(new Rectangle(30, 15, 365, 15));
        horizantalSub.setVisible(false);
        horizantalSub.setBackground(FormUtils.getColorFondo());

        verticalSub.setBounds(new Rectangle(15, 30, 15, 365));
        verticalSub.setOrientation(JSlider.VERTICAL);
        verticalSub.setValue(0);
        verticalSub.setInverted(true);
        verticalSub.setVisible(false);
        verticalSub.setBackground(FormUtils.getColorFondo());

        panelArbol.add(pintarArbol);
        panelSubArbol.add(pintarSubArbol);
        panelSubArbol.setVisible(false);

        tiempo.start();

        panelSeparator1.setVisible(false);
        panelSeparator2.setVisible(false);

        this.getContentPane().add(salirButton);
        this.getContentPane().add(nodosLabel);
        this.getContentPane().add(panelSeparator2);
        this.getContentPane().add(panelSeparator1);
        this.getContentPane().add(panelSubArbol);
        this.getContentPane().add(panelArbol);
        this.getContentPane().add(verticalSub);
        this.getContentPane().add(horizantalSub);
        this.getContentPane().add(horizontal);
        this.getContentPane().add(nuevoButton);
        this.getContentPane().add(respuestaLabel);
        this.getContentPane().add(elementoLabel);
        this.getContentPane().add(preguntaLabel);
        this.getContentPane().add(buscarEleText);
        this.getContentPane().add(tituoLabel);
        this.getContentPane().add(siguienteButton);
        this.getContentPane().add(atrazButton);
        this.getContentPane().add(pasoActualLabel);
        this.getContentPane().add(historialButton);
        this.getContentPane().add(scrool);
        this.getContentPane().add(insertarButton);
        this.getContentPane().add(insertarEleText);
        this.getContentPane().add(pasoSiguienteButton);
        this.getContentPane().add(directoButton);
        this.getContentPane().add(pasoAtrazButton);
        this.getContentPane().add(pasoLabel);
        this.getContentPane().add(nivelButton);
        this.getContentPane().add(existeButton);
        this.getContentPane().add(vertical);

    }

    private void actionInsertar() {

        if (isNumberValid(insertarEleText.getText())) {
            elemento = Integer.parseInt(insertarEleText.getText());
            if (!arbolRojoNegro.existe(elemento)) {// si no existe el elemento
                indexHistorialArbol = arbolRojoNegro.getLista().getSize();
                tiempo2.stop();
                tiempo3.stop();
                pintarArbol.repaint();
                pasoActualLabel.setText("Paso Actual");
                arbolRojoNegro.insertar(elemento);
                arbolRojoNegro.cargarcaLHistrial();
                arbolRojoNegro.cargarcaLPasosA();
                if (arbolRojoNegro.getRaiz().getRD() == null && arbolRojoNegro.getRaiz().getRI() == null || pasoPasoBool) {
                    pintarArbol.setArbol(arbolRojoNegro.actualizar(arbolRojoNegro.getRaiz()));
                    pintarArbol.pintar();
                }
                indexArbol = 0;
                indexPaso = 0;
                indexCasoChar = 0;
                pintarArbol.setIndexRecorrido(0);
                pintarArbol.setLc(arbolRojoNegro.getRecorridoList(), elemento);
                if (!pasoPasoBool) {
                    directoButton.setEnabled(false);
                    insertarButton.setEnabled(false);
                    pasoSiguienteButton.setEnabled(true);
                    pasoAtrazButton.setEnabled(true);

                } else {
                    insertarButton.setEnabled(true);
                }
                subArbolBool = false;
                textArea.setText("");
            } else {
                textArea.setText("EL elemento : " + elemento + " ya existe en ele arbol. Inserte otro elemento porfavor");
            }
        } else {
            textArea.setText("Elemento no valido");
        }
    }

    private void actionPasoSiguiente() {
        existeSeguientePasoBool = true;
        pasoActualLabel.setText("Paso Actual");
        if (pintarArbol.getIndexRecorrido() < arbolRojoNegro.getRecorridoList().getSize()) {
            pintarArbol.pintarCamino();
            pintarArbol.setIndexRecorrido(pintarArbol.getIndexRecorrido() + 1);
            textArea.setText((String) arbolRojoNegro.getPasosActualList().consultar(indexPaso) + "\n");
            indexPaso++;
        } else {
            if (indexArbol < arbolRojoNegro.getArbolList().getSize() - 2) {
                Nodo r = (Nodo) arbolRojoNegro.getArbolList().consultar(indexArbol + 1);
                textArea.setText((String) arbolRojoNegro.getPasosActualList().consultar(indexPaso) + "\n");
                if (indexArbol == 0) {
                    textArea.setText("Se reemplaza el Nodo externo por el nodo nuevo\n");
                    pintarArbol.setArbol(arbolRojoNegro.actualizar(r));
                    pintarArbol.pintar();
                } else {
                    if (indexArbol % 3 == 0) {
                        pintarArbol.setArbol(arbolRojoNegro.actualizar(r));
                        pintarArbol.pintar();
                        panelSubArbol.setVisible(false);
                        horizantalSub.setVisible(false);
                        verticalSub.setVisible(false);
                        panelSeparator1.setVisible(false);
                        panelSeparator2.setVisible(false);
                        indexPaso++;
                        tiempo2.stop();
                        tiempo3.stop();
                    } else {
                        subArbolBool = !subArbolBool;
                        if (indexCasoChar < arbolRojoNegro.getCasos().length()) {
                            int el = Integer.parseInt(arbolRojoNegro.getCasos().charAt(indexCasoChar) + "");
                            if (el == 1) {
                                tiempo2.start();
                                tiempo3.start();
                                caso = CasoArbol.fromId(Integer.parseInt(arbolRojoNegro.getCasos().charAt(indexCasoChar + 1) + ""));
                                textArea.append("Se Renombra los Nodos e, e1 y e2 con (A-B-C) de tal forma que un recorrido inorden \n del subarbol de la secuencia A ; B ; C. Luego B cambia por negro y A y C por rojo \n ");
                                indexCasoChar++;
                            } else {
                                tiempo3.start();
                                textArea.append("Se hace cambio de Colores:\nLa raiz(e) del subarbol se cambia a roja a e1 y su hermano por negro \n Si la raiz del subarbol resulta la misma que la del Arbol 'Principal' N O se hace la \n transformacion a la raiz pero si a e1 y su hermano");
                            }
                            indexCasoChar++;
                        }
                        pintarSubArbol.setArbol(arbolRojoNegro.actualizar(r));
                        pintarSubArbol.pintar();
                        panelSubArbol.setVisible(true);
                        horizantalSub.setVisible(true);
                        verticalSub.setVisible(true);
                        panelSeparator1.setVisible(true);
                        panelSeparator2.setVisible(true);

                    }
                }
                indexArbol++;
            } else {
                if (indexArbol == 0) {
                    textArea.setText("Se reemplaza el Nodo externo por el nodo nuevo\n");
                    pintarArbol.setArbol(arbolRojoNegro.actualizar(arbolRojoNegro.getRaiz()));
                    pintarArbol.pintar();
                    indexArbol++;
                } else {
                    tiempo2.stop();
                    tiempo3.stop();
                    insertarButton.setEnabled(true);
                    directoButton.setEnabled(true);
                    pasoSiguienteButton.setEnabled(false);
                    pasoAtrazButton.setEnabled(false);
                    pintarArbol.setArbol(arbolRojoNegro.actualizar(arbolRojoNegro.getRaiz()));
                    textArea.setText("No existe problema de ROJO  ROJO. \nPuede Insertar otro Numero");
                    pintarArbol.pintar();
                }
            }
        }
    }

    private void actionPasoAtraz() {
        existeSeguientePasoBool = false;
        panelSubArbol.setVisible(false);
        horizantalSub.setVisible(false);
        verticalSub.setVisible(false);
        panelSeparator1.setVisible(false);
        panelSeparator2.setVisible(false);
        textArea.setText("");
        if (indexArbol > 0) {
            indexArbol--;
            Nodo r1 = (Nodo) arbolRojoNegro.getArbolList().consultar(indexArbol);
            if (indexArbol == 0) {
                pintarArbol.setArbol(arbolRojoNegro.actualizar(r1));
                pintarArbol.pintar();
                indexPaso--;
            } else {
                if (indexArbol % 3 == 0) {
                    pintarArbol.setArbol(arbolRojoNegro.actualizar(r1));
                    pintarArbol.pintar();
                    panelSubArbol.setVisible(false);
                    horizantalSub.setVisible(false);
                    verticalSub.setVisible(false);
                    panelSeparator1.setVisible(false);
                    panelSeparator2.setVisible(false);
                    indexPaso--;
                    tiempo2.stop();
                    tiempo3.stop();
                } else {
                    pintarSubArbol.setArbol(arbolRojoNegro.actualizar(r1));
                    pintarSubArbol.pintar();
                    panelSubArbol.setVisible(true);
                    horizantalSub.setVisible(true);
                    verticalSub.setVisible(true);
                    panelSeparator1.setVisible(true);
                    panelSeparator2.setVisible(true);
                    tiempo3.start();
                    tiempo2.start();
                }
            }

        } else {
            tiempo3.stop();
            pintarArbol.setArbol(arbolRojoNegro.actualizar(arbolRojoNegro.getRaizAux()));
            pintarArbol.pintar();
        }
        pasoActualLabel.setText("Historial Act.");
        textArea.setText("");
        for (int i = 0; i < arbolRojoNegro.getPasosActualList().getSize(); i++) {
            textArea.append(arbolRojoNegro.getPasosActualList().consultar(i).toString() + "\n");
        }
    }

    private void actionDirecto() {
        if (pasoPasoBool) {
            FormUtils.updateButton(getClass(), directoButton, "pasoPaso1", "pasoPaso2", 820, 240);
            pasoSiguienteButton.setEnabled(false);
            pasoAtrazButton.setEnabled(false);
        } else {
            FormUtils.updateButton(getClass(), directoButton, "directo1", "directo2", 820, 240);
        }
        pasoSiguienteButton.setVisible(pasoPasoBool);
        pasoAtrazButton.setVisible(pasoPasoBool);
        pasoLabel.setVisible(pasoPasoBool);
        pasoPasoBool = !pasoPasoBool;
    }

    private void actionAtraz() {
        textArea.setText("");
        if (indexHistorialArbol > 0 && indexHistorialArbol <= arbolRojoNegro.getLista().getSize()) {
            pintarArbol.setArbol((Nodo) arbolRojoNegro.getLista().consultar(indexHistorialArbol - 1));
            pintarArbol.pintar();
            indexHistorialArbol--;
        }
        if (indexHistorialArbol == 0)
            textArea.setText("Arbol con el primer elemento ( ya no hay mas atras )");
    }

    private void actionSiguiente() {
        textArea.setText("");
        if (indexHistorialArbol < arbolRojoNegro.getLista().getSize() - 1 && indexHistorialArbol >= -1) {
            pintarArbol.setArbol((Nodo) arbolRojoNegro.getLista().consultar(indexHistorialArbol + 1));
            pintarArbol.pintar();
            indexHistorialArbol++;

        }
        if (indexHistorialArbol == arbolRojoNegro.getLista().getSize() - 1)
            textArea.setText("Arbol actual con todos los elementos (ya no hay mas adelante)");
    }

    private void actionHistorial() {
        pasoActualLabel.setText("Historial");
        textArea.setText("");
        for (int i = 0; i < arbolRojoNegro.getHistorialList().getSize(); i++) {
            textArea.append(arbolRojoNegro.getHistorialList().consultar(i).toString() + "\n");
        }
    }

    private void actionNivel() {
        if (isNumberValid(buscarEleText.getText())) {
            if (arbolRojoNegro.nivel(Integer.parseInt(buscarEleText.getText())) > -1)
                respuestaLabel.setText("El nivel de " + Integer.parseInt(buscarEleText.getText()) + " es " + arbolRojoNegro.nivel(Integer.parseInt(buscarEleText.getText())));
            else
                respuestaLabel.setText("No Existe");
        } else {
            respuestaLabel.setText("Elemento no valido");
        }
    }

    private void actionExiste() {
        if (isNumberValid(buscarEleText.getText())) {
            if (arbolRojoNegro.existe(Integer.parseInt(buscarEleText.getText())))
                respuestaLabel.setText("Existe el " + Integer.parseInt(buscarEleText.getText()));
            else
                respuestaLabel.setText("No existe el " + Integer.parseInt(buscarEleText.getText()));
        } else {
            respuestaLabel.setText("Elemento no valido");
        }
    }

    private void actionNuevo() {
        vertical.setValue(0);
        verticalSub.setValue(0);
        horizontal.setValue(50);
        horizantalSub.setValue(50);
        buscarEleText.setText("0");
        insertarEleText.setText("0");
        elemento = 0;

        arbolRojoNegro = new ArbolRojoNegro();
        pintarArbol.limpiar();
        textArea.setText("Nuevo arbol creado");

        pasoPasoBool = !pasoPasoBool;
        actionDirecto();
        insertarButton.setEnabled(true);
        directoButton.setEnabled(true);
    }

    private boolean isNumberValid(String number) {
        boolean bool = false;
        if (NumberUtils.isDigits(number)) {
            bool = (Integer.valueOf(number) > 0);
        }
        return bool;
    }
}
